/**
 *
 */
package com.fitbet.webpay.entity;

import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.DynamicUpdate;

import com.demo2do.core.wechat.entity.pay.PayOrder;
import com.fitbet.webpay.entity.prepare.PrepareRequest;

/**
 * @author downpour
 *
 */
@Entity
@Table(name = "tbl_payment_context")
@DynamicUpdate
public class PaymentContext implements Serializable, PayOrder {

    private static final long serialVersionUID = -992471455621974046L;

    @Id
    @GeneratedValue
    private Long id;

    /** (openid|userId) */
    private String userId;

    /** 支付渠道  */
    private String channel;

    /** 支付抬头  */
    private String subject;

    /** 支付金额  */
    private int amount;

    /** 状态  */
    @Enumerated(EnumType.ORDINAL)
    private PayStatus status;

    /** 支付凭证 */
    private String token;

    /** 订单号  */
    private String orderCode;

    /** 支付渠道返回的交易流水号 */
    private String transactionCode;

    /** 支付回调设置支付成功的时间  */
    private Date hookTime;

    /** 创建支付环境的时间   */
    private Date createTime;

    /** 最后更改时间 */
    private Date lastUpdateTime;

    /**
     * The default constructor
     */
    public PaymentContext() {

    }

    /**
     * The constructor using payment request and token
     *
     * @param prepareRequest
     */
    public PaymentContext(PrepareRequest prepareRequest) {
        this.userId = prepareRequest.getUserId();
        this.channel = PayChannel.codeOf(prepareRequest.getChannel()).getCode();
        this.subject = prepareRequest.getSubject();
        this.amount = prepareRequest.getAmount();
        this.status = PayStatus.WAITING;
        this.token = prepareRequest.getRequestNo();
        this.orderCode = prepareRequest.getOrderNo();
        this.createTime = new Date();
        this.lastUpdateTime = new Date();
    }

    /**
     * 
     * @param outTradeNo
     * @param totalFee
     * @return
     */
    public boolean matches(String outTradeNo, int totalFee) {
        return StringUtils.equals(outTradeNo, this.getOutTradeNo()) && totalFee == this.getAmount();
    }
    
    /**
     * Finish payment context with paid status
     *
     * @param transactionCode
     * @return
     */
    public PaymentContext paid(String transactionCode) {
        this.transactionCode = transactionCode;
        this.status = PayStatus.PAID;
        this.hookTime = new Date();
        this.lastUpdateTime = new Date();
        return this;
    }
    
    /**
     * get pay channel
     *
     * @return
     */
    public PayChannel getPayChannel() {
        return PayChannel.codeOf(this.channel);
    }

    /**
     *
     * @return
     */
    public String getAmountAsYuan() {
        DecimalFormat decimalFormat = new DecimalFormat("#0.00");
        return decimalFormat.format((1.0 * amount / 100));
    }

    /* (non-Javadoc)
     * @see com.demo2do.core.wechat.entity.pay.PayOrder#getOutTradeNo()
     */
    public String getOutTradeNo() {
        return this.token;
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.core.wechat.entity.pay.PayOrder#getAmountAsString()
     */
    public String getAmountAsString() {
        return String.valueOf(this.amount);
    }
    
    /**
     * @return the id
     */
    public Long getId() {
        return this.id;
    }

    /**
     * @return the userId
     */
    public String getUserId() {
        return userId;
    }

    /**
     * @return the channel
     */
    public String getChannel() {
        return this.channel;
    }

    /**
     * @return the subject
     */
    public String getSubject() {
        return this.subject;
    }

    /**
     * @return the amount
     */
    public int getAmount() {
        return this.amount;
    }

    /**
     * @return the status
     */
    public PayStatus getStatus() {
        return this.status;
    }

    /**
     * @return the token
     */
    public String getToken() {
        return this.token;
    }

    /**
     * @return the orderCode
     */
    public String getOrderCode() {
        return this.orderCode;
    }

    /**
     * @return the transactionCode
     */
    public String getTransactionCode() {
        return this.transactionCode;
    }

    /**
     * @return the hookTime
     */
    public Date getHookTime() {
        return this.hookTime;
    }

    /**
     * @return the createTime
     */
    public Date getCreateTime() {
        return this.createTime;
    }

    /**
     * @return the lastUpdateTime
     */
    public Date getLastUpdateTime() {
        return this.lastUpdateTime;
    }

    /**
     * @param id the id to set
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * 
     * @param userId the userId to set
     */
    public void setUserId(String userId) {
        this.userId = userId;
    }

    /**
     * @param channel the channel to set
     */
    public void setChannel(String channel) {
        this.channel = channel;
    }

    /**
     * @param subject the subject to set
     */
    public void setSubject(String subject) {
        this.subject = subject;
    }

    /**
     * @param amount the amount to set
     */
    public void setAmount(int amount) {
        this.amount = amount;
    }

    /**
     * @param status the status to set
     */
    public void setStatus(PayStatus status) {
        this.status = status;
    }

    /**
     * @param token the token to set
     */
    public void setToken(String token) {
        this.token = token;
    }

    /**
     * @param orderCode the orderCode to set
     */
    public void setOrderCode(String orderCode) {
        this.orderCode = orderCode;
    }

    /**
     * @param transactionCode the transactionCode to set
     */
    public void setTransactionCode(String transactionCode) {
        this.transactionCode = transactionCode;
    }

    /**
     * @param hookTime the hookTime to set
     */
    public void setHookTime(Date hookTime) {
        this.hookTime = hookTime;
    }

    /**
     * @param createTime the createTime to set
     */
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**
     * @param lastUpdateTime the lastUpdateTime to set
     */
    public void setLastUpdateTime(Date lastUpdateTime) {
        this.lastUpdateTime = lastUpdateTime;
    }
}
